#include "hw/qdev.h"
#include "sysemu/sysemu.h"
#include "qapi-types.h"
#include "qemu/error-report.h"
#include "qmp-commands.h"
//#include "trace.h"
#include "ui/input.h"
#include "ui/console.h"
#include "sysemu/replay.h"

struct QemuInputHandlerState {
    DeviceState       *dev;
    QemuInputHandler  *handler;
    int               id;
    int               events;
    QemuConsole       *con;
    QTAILQ_ENTRY(QemuInputHandlerState) node;
};

static QTAILQ_HEAD(, QemuInputHandlerState) handlers =
    QTAILQ_HEAD_INITIALIZER(handlers);

static QemuInputHandlerState*
qemu_input_find_handler(uint32_t mask, QemuConsole *con)
{
    QemuInputHandlerState *s;

    QTAILQ_FOREACH(s, &handlers, node) {
        if (s->con == NULL || s->con != con) {
            continue;
        }
        if (mask & s->handler->mask) {
            return s;
        }
    }

    QTAILQ_FOREACH(s, &handlers, node) {
        if (s->con != NULL) {
            continue;
        }
        if (mask & s->handler->mask) {
            return s;
        }
    }
    return NULL;
}

static void qemu_input_transform_abs_rotate(InputEvent *evt)
{
    switch (graphic_rotate) {
    case 90:
        if (evt->u.abs->axis == INPUT_AXIS_X) {
            evt->u.abs->axis = INPUT_AXIS_Y;
        } else if (evt->u.abs->axis == INPUT_AXIS_Y) {
            evt->u.abs->axis = INPUT_AXIS_X;
            evt->u.abs->value = INPUT_EVENT_ABS_SIZE - 1 - evt->u.abs->value;
        }
        break;
    case 180:
        evt->u.abs->value = INPUT_EVENT_ABS_SIZE - 1 - evt->u.abs->value;
        break;
    case 270:
        if (evt->u.abs->axis == INPUT_AXIS_X) {
            evt->u.abs->axis = INPUT_AXIS_Y;
            evt->u.abs->value = INPUT_EVENT_ABS_SIZE - 1 - evt->u.abs->value;
        } else if (evt->u.abs->axis == INPUT_AXIS_Y) {
            evt->u.abs->axis = INPUT_AXIS_X;
        }
        break;
    }
}

void qemu_input_event_send_impl(QemuConsole *src, InputEvent *evt)
{
    QemuInputHandlerState *s;

    //qemu_input_event_trace(src, evt);

    /* pre processing */
    if (graphic_rotate && (evt->type == INPUT_EVENT_KIND_ABS)) {
            qemu_input_transform_abs_rotate(evt);
    }

    /* send event */
    s = qemu_input_find_handler(1 << evt->type, src);
    if (!s) {
        return;
    }
    s->handler->event(s->dev, src, evt);
    s->events++;
}


void qemu_input_event_sync_impl(void)
{
    QemuInputHandlerState *s;

    //trace_input_event_sync();

    QTAILQ_FOREACH(s, &handlers, node) {
        if (!s->events) {
            continue;
        }
        if (s->handler->sync) {
            s->handler->sync(s->dev);
        }
        s->events = 0;
    }
}

